home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / PRINTERS / PostScript.C < prev    next >
C/C++ Source or Header  |  1992-08-26  |  28KB  |  1,058 lines

  1. #include "Object.h"         // cpp max nesting level...
  2.  
  3. #include "Class.h"
  4. #include "Error.h"
  5. #include "CLib.h"
  6. #include "System.h"
  7. #include "String.h"
  8. #include "DevBitmap.h"
  9. #include "OrdColl.h"
  10. #include "OneOfCluster.h"
  11. #include "ManyOfCluster.h"
  12. #include "Expander.h"
  13. #include "BorderItems.h"
  14. #include "Buttons.h"
  15. #include "Env.h"
  16. #include "Form.h"
  17. #include "PopupItem.h"
  18. #include "Menu.h"
  19. #include "Fields.h"
  20. #include "Math.h"
  21.  
  22. #include "Printer.h"
  23. #include "PrintPort.h"
  24. #include "PrintManager.h"
  25.  
  26. const int cIdName       =   cIdFirstUser + 1,
  27.       cIdOptions    =   cIdFirstUser + 10,
  28.       cIdResolution =   cIdFirstUser + 20,
  29.       cIdOrientation=   cIdFirstUser + 30,
  30.       cIdPaperFormat=   cIdFirstUser + 40;
  31.  
  32. const int cFirstFontId  =   1174711,
  33.       cFontMask     =   ~(eFaceUnderline|eFaceOutline|eFaceShadow);
  34.  
  35. char       *PsTmp   =   "etprt",
  36.        *LpPath  =   "/usr/ucb/lpr -P%s",
  37.        *TmpPath =   "/usr/tmp";
  38.        
  39. static struct PaperFormat {
  40.     char *name;
  41.     int width, height;
  42.     
  43.     Point Size()
  44.     { return Point(width, height); }
  45. } paperFormats[] = {
  46.     "A4 Letter",            595,    842,
  47.     "B5 Letter",            421,    595,
  48.     "US Letter",            615,    750,
  49.     "US Legal",             615,    842,
  50.     "US Envelope Centered", 615,    300,
  51.     0
  52. };
  53.  
  54. //---- PostScriptSettings ------------------------------------------------------------
  55.  
  56. class PostScriptSettings : public PrinterSettings {
  57. public:
  58.     float resolution;
  59.     bool portrait;
  60.     bool smooth;
  61.     bool wysiwyg;
  62.     bool prolog;
  63.     char *prname;
  64. public:
  65.     MetaDef(PostScriptSettings);
  66.     PostScriptSettings();
  67.     ~PostScriptSettings();
  68.     OStream& PrintOn(OStream &s);
  69.     IStream& ReadFrom(IStream &s);
  70. };
  71.  
  72. //---- PostScriptPort ----------------------------------------------------------
  73.  
  74. class PostScriptPort: public PrintPort {
  75. friend class RFont;
  76.     PostScriptSettings *pst;
  77.     bool tofile;
  78.     float xorigin, yorigin;
  79.     FILE *pfp, *prfp;
  80.     int lastpsz, maxfont, bcnt, pagecnt, currpage;
  81.     char *PrintTmpFile;
  82.     Font *lbfont, *lfont;
  83.     byte bbuf[MaxTextBatchCnt];
  84.     class OrdCollection *ProcSets, *Fonts;
  85.  
  86. protected:
  87.     void SetPenSize(int pensize);
  88.     void EnrollFont(Font *fd);
  89.     void UseProcSet(char *name);
  90.     Rectangle *PrintBBox(Rectangle &bbox);
  91.     void downloadfont(FILE *ofp, Font *fd, char *fname);
  92.  
  93. public:
  94.     MetaDef(PostScriptPort);
  95.     PostScriptPort(char *name, PostScriptSettings *pst);
  96.     ~PostScriptPort();
  97.     
  98.     void DevOpenPage(int pn);
  99.     void DevClosePage();
  100.     
  101.     void DevSetPattern(class DevBitmap*);
  102.     void DevSetOther(int);
  103.     void DevSetGrey(float f);
  104.     void DevSetColor(RGBColor *cp);
  105.     
  106.     void DevClip(Rectangle);
  107.     
  108.     void DevStrokeLine(int, Rectangle*, GrLineCap, Point, Point);
  109.     void DevStrokeRect(int, Rectangle*);
  110.     void DevFillRect(Rectangle*);
  111.     void DevStrokeOval(int, Rectangle*);
  112.     void DevFillOval(Rectangle*);
  113.     void DevStrokeRRect(int, Rectangle*, Point);
  114.     void DevFillRRect(Rectangle*, Point);
  115.     void DevStrokeWedge(int, GrLineCap, Rectangle*, int, int);
  116.     void DevFillWedge(Rectangle*, int, int);
  117.     void DevStrokePolygon(Rectangle*, Point*, int, GrPolyType t, int, GrLineCap);
  118.     void DevFillPolygon(Rectangle*, Point*, int, GrPolyType t);
  119.     void DevShowBitmap(Rectangle*, struct Bitmap*);
  120.     void DevShowChar(Font *fdp, Point pos, byte c, Rectangle*);
  121.     void DevShowTextBatch(Rectangle*, Point);
  122.     void DevGiveHint(int, int, void*);
  123.     bool DevScale(float sx, float sy);
  124. };
  125.  
  126. //---- PostScriptPrinter -------------------------------------------------------
  127.  
  128. class PostScriptPrinter : public Printer {
  129.     OneOfCluster *orientation;
  130.     FloatField *resolution;
  131.     ManyOfCluster *options;
  132.     TextField *eti;
  133.     Menu *paperFormatMenu;
  134.     PopupButton *paperFormatPopup;
  135. public:
  136.     MetaDef(PostScriptPrinter);
  137.     PostScriptPrinter()
  138.     { }
  139.     char *GetName()
  140.     { return "PostScript"; }
  141.     PrintPort *MakePrintPort(char *name)
  142.     { return new PostScriptPort(name, (PostScriptSettings*) settings); }
  143.     bool CanSave()
  144.     { return TRUE; }
  145.     bool CanPrint()
  146.     { return TRUE; }
  147.     PrinterSettings *MakeSettings()
  148.     { return new PostScriptSettings; }
  149.     VObject *DoCreatePrintDialog();
  150.     void LoadSettings(PrinterSettings*);
  151.     void StoreSettings(PrinterSettings*);
  152. };
  153.  
  154. //---- FMap --------------------------------------------------------------------
  155.  
  156. static struct FMap {
  157.     char *name;
  158.     int encode;
  159.     GrFont fid;
  160.     GrFace face;
  161. } fmap[] = {
  162.     "AvantGarde-Book",                1, eFontAvantgarde, eFacePlain,
  163.     "AvantGarde-BookOblique",         1, eFontAvantgarde, eFaceItalic,
  164.     "AvantGarde-Demi",                1, eFontAvantgarde, eFaceBold,
  165.     "AvantGarde-DemiOblique",         1, eFontAvantgarde, (GrFace)(eFaceItalic | eFaceBold),
  166.     "Bookman-Light",                  1, eFontBookman, eFacePlain,
  167.     "Bookman-LightItalic",            1, eFontBookman, eFaceItalic,
  168.     "Bookman-Demi",                   1, eFontBookman, eFaceBold,
  169.     "Bookman-DemiItalic",             1, eFontBookman, (GrFace)(eFaceItalic | eFaceBold),
  170.     "Courier",                        1, eFontCourier, eFacePlain,
  171.     "Courier-Oblique",                1, eFontCourier, eFaceItalic,
  172.     "Courier-Bold",                   1, eFontCourier, eFaceBold,
  173.     "Courier-BoldOblique",            1, eFontCourier, (GrFace)(eFaceItalic | eFaceBold),
  174.     "Helvetica",                      1, eFontHelvetica, eFacePlain,
  175.     "Helvetica-Oblique",              1, eFontHelvetica, eFaceItalic,
  176.     "Helvetica-Bold",                 1, eFontHelvetica, eFaceBold,
  177.     "Helvetica-BoldOblique",          1, eFontHelvetica, (GrFace)(eFaceItalic | eFaceBold),
  178.     "Helvetica-Narrow",               1, eFontNHelvetica, eFacePlain,
  179.     "Helvetica-Narrow-Oblique",       1, eFontNHelvetica, eFaceItalic,
  180.     "Helvetica-Narrow-Bold",          1, eFontNHelvetica, eFaceBold,
  181.     "Helvetica-Narrow-BoldOblique",   1, eFontNHelvetica, (GrFace)(eFaceItalic | eFaceBold),
  182.     "NewCenturySchlbk-Roman",         1, eFontSchoolbook, eFacePlain,
  183.     "NewCenturySchlbk-Italic",        1, eFontSchoolbook, eFaceItalic,
  184.     "NewCenturySchlbk-Bold",          1, eFontSchoolbook, eFaceBold,
  185.     "NewCenturySchlbk-BoldItalic",    1, eFontSchoolbook, (GrFace)(eFaceItalic | eFaceBold),
  186.     "Palatino-Roman",                 1, eFontPalatino, eFacePlain,
  187.     "Palatino-Italic",                1, eFontPalatino, eFaceItalic,
  188.     "Palatino-Bold",                  1, eFontPalatino, eFaceBold,
  189.     "Palatino-BoldItalic",            1, eFontPalatino, (GrFace)(eFaceItalic | eFaceBold),
  190.     "Symbol",                         0, eFontSymbol, eFacePlain,
  191.     "Times-Roman",                    1, eFontTimes, eFacePlain,
  192.     "Times-Italic",                   1, eFontTimes, eFaceItalic,
  193.     "Times-Bold",                     1, eFontTimes, eFaceBold,
  194.     "Times-BoldItalic",               1, eFontTimes, (GrFace)(eFaceItalic | eFaceBold),
  195.     "ZapfChancery-MediumItalic",      1, eFontChancery, eFacePlain,
  196.     "ZapfDingbats",                   0, eFontDingbats, eFacePlain,
  197.     0
  198. };
  199.  
  200. static FMap *FindFont(GrFont fid, GrFace face)
  201. {
  202.     int i;
  203.     for (i= 0; fmap[i].name; i++)
  204.     if (fmap[i].fid == fid && fmap[i].face == face)
  205.         return &fmap[i];
  206.     return 0;
  207. }
  208.  
  209. static char *MapName(GrFont fid, GrFace face)
  210. {
  211.     FMap *fm= FindFont(fid, (GrFace)(face & cFontMask));
  212.     if (fm)
  213.     return fm->name;
  214.     return gFontManager->IdToName(fid);
  215. }
  216.  
  217. static bool IsPSFont(GrFont fid)
  218. {
  219.     FMap *fm= FindFont(fid, eFacePlain);
  220.     if (fm)
  221.     return TRUE;
  222.     return FALSE;
  223. }
  224.  
  225. static bool Reencode(GrFont fid)
  226. {
  227.     FMap *fm= FindFont(fid, eFacePlain);
  228.     if (fm)
  229.     return fm->encode;
  230.     return FALSE;
  231. }
  232.  
  233. static char *EtName(GrFont fid, GrFace face)
  234. {
  235.     return form("%s-%s", gFontManager->IdToName(fid),
  236.     gFontManager->StyleString((GrFace)(face & cFontMask)));
  237. }
  238.  
  239. //---- output functions ---------------------------------------------------------
  240.  
  241. /*
  242.  %c  PostScript character       byte
  243.  %f  floating point             float
  244.  %d  integer                    integer
  245.  %x  2-digit hex num            byte
  246.  %r  Rectangle                  Rectangle*
  247.  %p  Point                      Point
  248.  %s  0-terminated string        char*
  249. */
  250.  
  251. static void Printf(FILE *pfp, char *va_(format), ...)
  252. {
  253.     static char *t= "0123456789abcdef";
  254.     register char c;
  255.     unsigned int b;
  256.     char *s;
  257.     Point *p;
  258.     int i;
  259.     double d;
  260.     Rectangle *r;
  261.     va_list ap;
  262.     
  263.     va_start(ap,va_(format));
  264.     char *fmt= va_(format);
  265.     
  266.     while (c= *fmt++) {
  267.     switch (c) {
  268.     case '%':
  269.         switch (c= *fmt++) {
  270.         case '%':
  271.         fputc('%', pfp);
  272.         break;
  273.         case 'c':
  274.         b= va_arg(ap, unsigned int);
  275.         if (b >= ' ' && b <= '~') {
  276.             if (b == '\\' || b == '(' || b == ')')
  277.             fputc('\\', pfp); 
  278.             fputc(b, pfp);
  279.         } else
  280.             fprintf(pfp, "\\%03o", b);
  281.         break;
  282.         case 'f':
  283.         d= va_arg(ap, double);
  284.         fprintf(pfp, "%.3f", d);
  285.         break;
  286.         case 'd':
  287.         i= va_arg(ap, int);
  288.         fprintf(pfp, "%d", i);
  289.         break;
  290.         case 'x':
  291.         b= va_arg(ap, unsigned int);
  292.         fputc(t[(b&0xff)>>4], pfp);
  293.         fputc(t[b&0xf], pfp);
  294.         break;
  295.         case 's':
  296.         s= va_arg(ap, char*);
  297.         while (c= *s++)
  298.             fputc(c, pfp);
  299.         break;
  300.         case 'r':
  301.         r= va_arg(ap, Rectangle*);
  302.         fprintf(pfp, "%d %d %d %d", r->origin.x, r->origin.y, r->extent.x,
  303.                                   r->extent.y);
  304.         break;
  305.         case 'p':
  306.         p= va_arg(ap, Point*);
  307.         fprintf(pfp, "%d %d", (int) p->x, (int) p->y);
  308.         break;
  309.         default:
  310.         fputc(c, pfp);
  311.         break;
  312.         }
  313.         break;
  314.     default:
  315.         fputc(c, pfp);
  316.         break;
  317.     }
  318.     }
  319.     va_end(ap);
  320. }
  321.  
  322. //---- PostScriptSettings ------------------------------------------------------------
  323.  
  324. NewMetaImpl(PostScriptSettings, PrinterSettings, (T(resolution), TB(portrait),
  325.                 TB(smooth), TB(wysiwyg), TB(prolog), TS(prname)));
  326.  
  327. PostScriptSettings::PostScriptSettings()
  328.         : PrinterSettings(Point(595, 842), Point(50), Point(50), gRect0)
  329. {
  330.     portrait= prolog= TRUE;
  331.     smooth= wysiwyg= FALSE;
  332.     resolution= 1.0;
  333.     prname= strsave(Env::GetValue("PRINTER", "lp"));
  334. }
  335.  
  336. PostScriptSettings::~PostScriptSettings()
  337. {
  338.     SafeDelete(prname);
  339. }
  340.  
  341. OStream& PostScriptSettings::PrintOn (OStream &s)
  342. {
  343.     PrinterSettings::PrintOn(s);
  344.     return s << portrait SP << prolog SP << smooth SP
  345.             << wysiwyg SP << resolution SP << prname SP;
  346. }
  347.  
  348. IStream& PostScriptSettings::ReadFrom(IStream &s)
  349. {
  350.     char buf[100];
  351.     PrinterSettings::ReadFrom(s);
  352.     s >> portrait >> prolog >> smooth >> wysiwyg >> resolution >> buf;
  353.     SafeDelete(prname);
  354.     prname= strsave(buf);
  355.     return s;
  356. }
  357.  
  358. //---- PSResource --------------------------------------------------------------
  359.  
  360. class PSResource : public Object {
  361.     static char *lasttag;
  362. protected:
  363.     char *type, *name;
  364.     bool supplied;
  365. public:
  366.     PSResource(char *t, bool suppl)
  367.     { type= t; supplied= suppl; name= 0; }
  368.     ~PSResource()
  369.     { SafeDelete(name); }
  370.     char *GetName()
  371.     { return name; }
  372.     void Load(FILE *ofp);
  373.     virtual void load(FILE *ofp) = 0;
  374.     void Do(FILE *ofp, char *t);
  375.     void Used(FILE *ofp)
  376.     { Do(ofp, ""); }
  377.     void Supplied(FILE *ofp)
  378.     { if (supplied) Do(ofp, "Supplied"); }
  379.     void Needed(FILE *ofp)
  380.     { if (!supplied) Do(ofp, "Needed"); }
  381. };
  382.  
  383. char *PSResource::lasttag;
  384.  
  385. void PSResource::Load(FILE *ofp)
  386. {
  387.     if (supplied)
  388.     load(ofp);
  389.     else
  390.     Printf(ofp, "%%%%Include%s: %s\n", type, name);
  391. }
  392.  
  393. void PSResource::Do(FILE *ofp, char *t)
  394. {
  395.     if (lasttag == 0 || strcmp(lasttag, t) != 0) {
  396.     Printf(ofp, "%%%%Document%s%ss: %s\n", t, type, name);
  397.     lasttag= t;
  398.     } else
  399.     Printf(ofp, "%%%%+ %s\n", name);
  400. }
  401.  
  402. //---- ProcSet -----------------------------------------------------------------
  403.  
  404. class ProcSet : public PSResource {
  405. public:
  406.     ProcSet(char *n, bool pro) : PSResource("ProcSet", pro)
  407.     { name= strsave(n); }
  408.     void load(FILE *ofp);
  409. };
  410.  
  411. void ProcSet::load(FILE *ofp)
  412. {
  413.     char buf[256];
  414.     for (int i= 0; name[i]; i++) {
  415.     if (name[i] == ' ')
  416.         buf[i]= '-';
  417.     else
  418.         buf[i]= name[i];
  419.     }
  420.     buf[i]= 0;
  421.     FILE *fin= fopen(form("%s/postscript/%s.ps", gEtDir, buf), "r");
  422.     if (fin) {
  423.     while (fgets(buf, sizeof(buf), fin))
  424.         fputs(buf, ofp);
  425.     fclose(fin);
  426.     } else
  427.     fprintf(stderr, "can't load procset <%s>\n", buf);
  428. }
  429.  
  430. //---- RFont -------------------------------------------------------------------
  431.  
  432. class RFont : public PSResource {
  433.     PostScriptPort *psp;
  434. public:
  435.     GrFont fid;
  436.     GrFace face;
  437. public:
  438.     RFont(PostScriptPort *p, GrFont fd, GrFace fc);
  439.     void load(FILE *ofp)
  440.     {  psp->downloadfont(ofp, new_Font(fid, 12, face, TRUE), name); }
  441.     void SetUp(FILE *ofp);
  442. };
  443.  
  444. RFont::RFont(PostScriptPort *p, GrFont fd, GrFace fc)
  445.                         : PSResource("Font", !IsPSFont(fd))
  446. {
  447.     psp= p;
  448.     fid= fd;
  449.     face= fc;
  450.     name= strsave(MapName(fd, fc));
  451. }
  452.  
  453. void RFont::SetUp(FILE *ofp)
  454. {
  455.     Printf(ofp, "/%s /%s findfont def\n", EtName(fid, face), name);
  456.     if (Reencode(fid))
  457.     Printf(ofp, "/%s Reencode\n", EtName(fid, face));
  458. }
  459.  
  460. //---- PostScriptPort ----------------------------------------------------------
  461.  
  462. NewMetaImpl0(PostScriptPort, PrintPort);
  463.  
  464. PostScriptPort::PostScriptPort(char *name, PostScriptSettings *st) : PrintPort(name)
  465. {
  466.     pst= st;
  467.     
  468.     hascolor= TRUE;
  469.  
  470.     ProcSets= new OrdCollection;
  471.     Fonts= new OrdCollection;
  472.     
  473.     xorigin= 0.0;
  474.     yorigin= (pst->portrait) ? 842.0 : 0.0;      
  475.  
  476.     tofile= (name != 0);
  477.     pagecnt= 0;
  478.     
  479.     UseProcSet("et 2.2 0");
  480.  
  481.     if (tofile)
  482.     prfp= fopen(name, "w");
  483.     else
  484.     prfp= popen(form(LpPath, pst->prname), "w");
  485.      
  486.     PrintTmpFile= tempnam((char*) TmpPath, (char*) PsTmp);
  487.  
  488.     if (PrintTmpFile == NULL)
  489.     fprintf(stderr, "PostScriptPort::PostScriptPort: can't create tmpfile\n");
  490.     if ((pfp= fopen(PrintTmpFile, "w")) == NULL)
  491.     fprintf(stderr, "PostScriptPort::PostScriptPort: can't open tmpfile\n");
  492.     
  493.     Printf(prfp, "%%!PS-Adobe-1.0\n");
  494.     Printf(prfp, "%%%%Title: title\n");
  495.     Printf(prfp, "%%%%Creator: ET++\n");
  496.     Printf(prfp, "%%%%CreationDate: date\n");
  497.     Printf(prfp, "%%%%For: User\n");
  498.     Printf(prfp, "%%%%DocumentData: Clean7Bit\n");
  499.     Printf(prfp, "%%%%LanguageLevel: 1\n");
  500.     Printf(prfp, "%%%%Orientation: %s\n", pst->portrait ? "Portrait"
  501.                             : "Landscape");
  502.     Printf(prfp, "%%%%PageOrder: Ascend\n");
  503.     Printf(prfp, "%%%%Version: 2.2 1\n");
  504. }
  505.  
  506. PostScriptPort::~PostScriptPort()
  507. {
  508.     FlushMyText();
  509.     
  510.     Printf(pfp, "%%%%Trailer\n");
  511.     Printf(pfp, "end\n");
  512.     Printf(pfp, "%%%%EOF\n");
  513.     
  514.     fclose(pfp);
  515.     
  516.     { ProcSets->ForEach(ProcSet,Used)(prfp); }
  517.     { ProcSets->ForEach(ProcSet,Supplied)(prfp); }
  518.     { ProcSets->ForEach(ProcSet,Needed)(prfp); }
  519.  
  520.     { Fonts->ForEach(RFont,Used)(prfp); }
  521.     { Fonts->ForEach(RFont,Supplied)(prfp); }
  522.     { Fonts->ForEach(RFont,Needed)(prfp); }
  523.  
  524.     Printf(prfp, "%%%%Pages: %d\n", pagecnt);
  525.     Printf(prfp, "%%%%BoundingBox: %r\n", PrintBBox(bbox));
  526.     Printf(prfp, "%%%%EndComments\n");
  527.  
  528.     Printf(prfp, "%%%%BeginProlog\n");
  529.     { ProcSets->ForEach(ProcSet,Load)(prfp); }
  530.     Printf(prfp, "%%%%EndProlog\n");
  531.     
  532.     Printf(prfp, "%%%%BeginSetup\n");
  533.     Printf(prfp, "ET++Dict begin\n");
  534.     { Fonts->ForEach(RFont,Load)(prfp); }
  535.     { Fonts->ForEach(RFont,SetUp)(prfp); }
  536.  
  537.     Printf(prfp, "%%%%EndSetup\n");
  538.  
  539.     {
  540.     char buf[256];
  541.     register FILE *rpfp;
  542.     
  543.     if ((rpfp= fopen(PrintTmpFile, "r")) == NULL) {
  544.         fprintf(stderr, "PostScriptPort::~PostScriptPort: can't open tmpfile %s\n", PrintTmpFile);
  545.         return;
  546.     }
  547.     
  548.     while (fgets(buf, sizeof(buf), rpfp) != NULL)
  549.         fputs(buf, prfp);
  550.     fclose(rpfp);
  551.     CLib::Unlink(PrintTmpFile);
  552.     }
  553.     
  554.     if (tofile)
  555.     fclose(prfp);
  556.     else
  557.     pclose(prfp);
  558.     
  559.     if (ProcSets) {
  560.     ProcSets->FreeAll();
  561.     SafeDelete(ProcSets);
  562.     }
  563.     if (Fonts) {
  564.     Fonts->FreeAll();
  565.     SafeDelete(Fonts);
  566.     }
  567. }
  568.  
  569. Rectangle *PostScriptPort::PrintBBox(Rectangle &bbox)
  570. {
  571.     static Rectangle r;
  572.     r.origin.x= (int)(xorigin + pst->resolution*bbox.origin.x - 0.5),
  573.     r.origin.y= (int)(yorigin - pst->resolution*(bbox.origin.y + bbox.extent.y) - 0.5),
  574.     r.extent.x= (int)(xorigin + pst->resolution*(bbox.origin.x + bbox.extent.x) + 0.5),
  575.     r.extent.y= (int)(yorigin - pst->resolution*bbox.origin.y + 0.5);
  576.     return &r;
  577. }
  578.  
  579. //---- Open, Close -------------------------------------------------------------
  580.  
  581. void PostScriptPort::DevOpenPage(int pn)
  582. {
  583.     lastpsz= -1;
  584.     lbfont= 0;
  585.     currpage= pn;
  586.     Printf(pfp, "%%%%Page: %d %d\n", pagecnt+1, currpage);
  587.     Printf(pfp, "%%%%PageBoundingBox: (atend)\n");
  588.     Printf(pfp, "%%%%BeginPageSetup\n");
  589.     Printf(pfp, "save\n");
  590.     Printf(pfp, "%f %f %d %f init\n", xorigin, yorigin, pst->portrait ? 0 : 90,
  591.                                 pst->resolution);
  592.     Printf(pfp, "%%%%EndPageSetup\n");
  593. }
  594.  
  595. void PostScriptPort::DevClosePage()
  596. {
  597.     Printf(pfp, "Restore\n");
  598.     if (pagebbox.IsNotEmpty()) {
  599.     if (gDebug)
  600.         Printf(pfp, "%r StrokeBBox\n", PrintBBox(pagebbox));
  601.     Printf(pfp, "showpage\n");
  602.     pagecnt++;
  603.     }
  604.     Printf(pfp, "%%%%PageTrailer\n");
  605.     Printf(pfp, "%%%%PageBoundingBox: %r\n", PrintBBox(pagebbox));
  606. }
  607.  
  608. //---- clipping ----------------------------------------------------------------
  609.  
  610. void PostScriptPort::DevClip(Rectangle r)
  611. {
  612.     Printf(pfp, "%r SetClip\n", &r);
  613.     lastpsz= -1;
  614.     lbfont= 0;
  615. }
  616.  
  617. bool PostScriptPort::DevScale(float sx, float sy)
  618. {
  619.     Printf(pfp, "%f %f scale\n", sx, sy);
  620.     return TRUE;
  621. }
  622.  
  623. //---- color -------------------------------------------------------------------
  624.  
  625. void PostScriptPort::DevSetGrey(float f)
  626. {
  627.     Printf(pfp, "%f SetGray\n", f);
  628. }
  629.  
  630. void PostScriptPort::DevSetColor(RGBColor *cp)
  631. {
  632.     Printf(pfp, "%f %f %f setrgbcolor\n", cp->GetRed() / 255.0,
  633.                       cp->GetGreen() / 255.0,
  634.                       cp->GetBlue() / 255.0);
  635.     //DevSetGrey(cp->AsGreyLevel() / 255.0);
  636.     cp->SetId(-1);
  637. }
  638.  
  639. void PostScriptPort::DevSetPattern(DevBitmap *bmp)
  640. {
  641.     Printf(pfp, "<");
  642.     for (int y= 0; y < bmp->Size().y; y++)
  643.     Printf(pfp, "%x", bmp->GetByte(0, y));
  644.     Printf(pfp, "> SetPattern\n");
  645. }
  646.  
  647. void PostScriptPort::DevSetOther(int pid)
  648. {
  649.     Printf(pfp, "%f SetGray\n", pid == 1 ? 1.0 : 0.0);
  650. }
  651.  
  652. void PostScriptPort::SetPenSize(int pensize)
  653. {
  654.     if (pensize < 0 || (pensize == lastpsz))
  655.     return;
  656.     lastpsz= pensize;
  657.     Printf(pfp, "%d SetPenSize\n", pensize);
  658. }
  659.  
  660. //---- drawing -----------------------------------------------------------------
  661.  
  662. void PostScriptPort::DevStrokeLine(int pensize, Rectangle *r,
  663.         GrLineCap cap, Point p1, Point p2)
  664. {
  665.     SetPenSize(pensize);
  666.     Merge(r);
  667.     Printf(pfp, "%p %p %d StrokeArrow\n", &p1, &p2, cap);
  668. }
  669.  
  670. void PostScriptPort::DevStrokeRect(int psz, Rectangle *r)
  671. {
  672.     Merge(r);
  673.     SetPenSize(psz);
  674.     Printf(pfp, "%r StrokeRect\n", r);
  675. }
  676.  
  677. void PostScriptPort::DevFillRect(Rectangle *r)
  678. {
  679.     Merge(r);
  680.     Printf(pfp, "%r FillRect\n", r);
  681. }
  682.  
  683. void PostScriptPort::DevStrokeOval(int psz, Rectangle *r)
  684. {
  685.     Merge(r);
  686.     SetPenSize(psz);
  687.     Printf(pfp, "%r StrokeOval\n", r);
  688. }
  689.  
  690. void PostScriptPort::DevFillOval(Rectangle *r)
  691. {
  692.     Merge(r);
  693.     Printf(pfp, "%r FillOval\n", r);
  694. }
  695.  
  696. void PostScriptPort::DevStrokeRRect(int psz, Rectangle *r, Point dia)
  697. {
  698.     Merge(r);
  699.     SetPenSize(psz);
  700.     Printf(pfp, "%r %p StrokeRoundRect\n", r, &dia);
  701. }
  702.  
  703. void PostScriptPort::DevFillRRect(Rectangle *r, Point dia)
  704. {
  705.     Merge(r);
  706.     Printf(pfp, "%r %p FillRoundRect\n", r, &dia);
  707. }
  708.  
  709. void PostScriptPort::DevStrokeWedge(int psz, GrLineCap, Rectangle *r, int s, int d)
  710. {
  711.     Point e(s, d);
  712.     Merge(r);
  713.     SetPenSize(psz);
  714.     Printf(pfp, "%r %p StrokeWedge\n", r, &e);
  715. }
  716.  
  717. void PostScriptPort::DevFillWedge(Rectangle *r, int s, int d)
  718. {
  719.     Point e(s, d);
  720.     Merge(r);
  721.     Printf(pfp, "%r %p FillWedge\n", r, &e);
  722. }
  723.  
  724. void PostScriptPort::DevStrokePolygon(Rectangle *r, Point *pts,
  725.                 int npts, GrPolyType t, int psz, GrLineCap)
  726. {
  727.     Merge(r);    
  728.     SetPenSize(psz);
  729.     Printf(pfp, "%r %d %d %p [\n", r, (pts[0] == pts[npts-1]) ? 1 : 0,
  730.                  (t & ePolyBezier) ? 1 : 0, &r->extent);
  731.     for (int i= 0; i < npts; i++)
  732.     Printf(pfp, "%p ", &pts[i]);
  733.     Printf(pfp, "\n] StrokePoly\n");
  734. }
  735.  
  736. void PostScriptPort::DevFillPolygon(Rectangle *r, Point *pts, int npts,
  737.                                 GrPolyType t) 
  738. {
  739.     Merge(r);
  740.     Printf(pfp, "%r %d %d %p [\n", r, (pts[0] == pts[npts-1]) ? 1 : 0,
  741.                  (t & ePolyBezier) ? 1 : 0, &r->extent);
  742.     for (int i= 0; i < npts; i++)
  743.     Printf(pfp, "%p ", &pts[i]);
  744.     Printf(pfp, "\n] FillPoly\n");
  745. }
  746.  
  747. //---- text batching -----------------------------------------------------------
  748.  
  749. void PostScriptPort::DevShowChar(Font *fdp, Point delta, byte c, Rectangle*)
  750. {
  751.     if (fdp != lfont || delta != gPoint0)
  752.     FlushAnyText();
  753.     
  754.     if (bcnt == 0)  // first
  755.     lfont= fdp;
  756.  
  757.     bbuf[bcnt++]= c;
  758. }
  759.  
  760. void PostScriptPort::DevShowTextBatch(Rectangle *r, Point pos)
  761. {
  762.     int i, w= 0;
  763.     register byte c;
  764.     
  765.     Merge(r);
  766.     if (lbfont != lfont) {
  767.     EnrollFont(lfont);
  768.     Printf(pfp, "%s %d scalesetfont\n",
  769.             EtName(lfont->Fid(), lfont->Face()), lfont->Size());
  770.     lbfont= lfont;
  771.     }
  772.     if (bcnt > 0) {
  773.     Printf(pfp, "%p m(", &pos);
  774.     for (i= 0; i < bcnt; i++) {
  775.         c= bbuf[i];
  776.         w+= lfont->Width(c);
  777.         Printf(pfp, "%c", c);
  778.     }
  779.     if (bcnt > 1)
  780.         Printf(pfp, ") %d sshow\n", w);
  781.     else       
  782.         Printf(pfp, ") show\n");
  783.     bcnt= 0;       
  784.     }
  785. }
  786.  
  787. //---- bitmaps & images --------------------------------------------------------
  788.  
  789. void PostScriptPort::DevShowBitmap(Rectangle *r, Bitmap *bm)
  790. {
  791.     int bytes, x, y, by, lines, yy;
  792.     Point e= bm->Size();
  793.     DevBitmap *bmp= bm->GetDevBitmap();
  794.     
  795.     Merge(r);
  796.     if (!gDebug && pst->smooth) {
  797.     bytes= bm->ShortsPerLine() * 2;
  798.     lines= 1250 / bytes;
  799.     
  800.     UseProcSet("smooth 2.2 0");
  801.     Printf(pfp, "%d %d div %d %d div %p %d %d SmoothBitmapStart\n",
  802.            r->extent.x, e.x, r->extent.y, e.y, &r->origin, bytes, e.x);
  803.     for (by= 0, y= 0; y < e.y; y+= by) {
  804.         by= Math::Min(lines, e.y-y);
  805.         Printf(pfp, "%d Band\n", by);
  806.         for(yy= y-2; yy < y+by+2; yy++) {
  807.         for (x= 0; x < bytes; x++)
  808.             Printf(pfp, "%x", bmp->GetByte(x, yy));
  809.         Printf(pfp, "\n");
  810.         }
  811.     }
  812.     Printf(pfp, "SmoothBitmapEnd\n");
  813.     } else {
  814.     Printf(pfp, "%r %p %d Bitmap\n", r, &e, bmp->Depth());
  815.     if (bmp->Depth() == 1) {
  816.         bytes= bmp->BytesPerLine(); // postscript images are Byte aligned
  817.         for (y= 0; y < e.y; y++) {
  818.         for (x= 0; x < bytes; x++)
  819.             Printf(pfp, "%x", bmp->GetByte(x, y));
  820.         Printf(pfp, "\n");
  821.         }
  822.     } else {
  823.         bytes= bmp->BytesPerLine(); /* postscript images are Byte aligned */
  824.         int cmssize= bmp->GetColormapSize();
  825.         int *grey= new int[cmssize];
  826.  
  827.         for (int i= 0; i < cmssize; i++)
  828.         grey[i]= bmp->GetColormapEntry(i).AsGreyLevel();
  829.  
  830.         for (y= 0; y < e.y; y++) {
  831.         for (x= 0; x < bytes; x++)
  832.             Printf(pfp, "%x", grey[bmp->GetPixel(x, y)]);
  833.         Printf(pfp, "\n");
  834.         }
  835.         delete grey;
  836.     }
  837.     }
  838. }
  839.  
  840. //---- hints -------------------------------------------------------------------
  841.  
  842. void PostScriptPort::DevGiveHint(int code, int, void *vp)
  843. {
  844.     char buf[300];
  845.     
  846.     switch (code) {
  847.     
  848.     case 55:
  849.     Printf(pfp, "%d %d translate\n", origin.x, origin.y);
  850.     break;
  851.  
  852.     case 55559:
  853.     if (sscanf((char*)vp, "%s", buf) == 1) {
  854.         FILE *fp;
  855.         if (fp= fopen(buf, "r")) {
  856.         while (fgets(buf, 299, fp))
  857.             if (buf[0] != '%')
  858.             fputs(buf, pfp);
  859.         fclose(fp);
  860.         }
  861.     }
  862.     break;
  863.     case eHintPostScript:
  864.     Printf(pfp, "%s", (char*) vp);
  865.     break;
  866.     case eHintEPSFStart:
  867.     Printf(pfp, "BeginEPSF\n");
  868.     ignore= TRUE;
  869.     break;
  870.     case eHintEPSFEnd:
  871.     Printf(pfp, "EndEPSF\n");
  872.     ignore= FALSE;
  873.     break;
  874.     case 66666:
  875.     byte *dash= (byte*) vp;
  876.     Printf(pfp, "[");
  877.     for (int i= 0; i < dash[2]; i++)
  878.         Printf(pfp, " %d", dash[i+3]);
  879.     Printf(pfp, "] %d setdash\n", dash[0]);
  880.     break;
  881.     case 66667:
  882.     Printf(pfp, "%s", "[] 0 setdash\n");
  883.     break;
  884.     case 77777: // RotateBegin
  885.     Printf(pfp, "%s", (char*) vp);
  886.     break;
  887.     case 77778: // RotateBegin
  888.     Printf(pfp, "%s", (char*) vp);
  889.     break;
  890.     }
  891. }
  892.  
  893. //---- misc functions ---------------------------------------------------------
  894.  
  895. void PostScriptPort::EnrollFont(Font *fd)
  896. {
  897.     Iter next(Fonts);
  898.     register RFont *rf;
  899.     
  900.     while (rf= (RFont*) next())
  901.     if (fd->Fid() == rf->fid && fd->Face() == rf->face)
  902.         return;
  903.         
  904.     Fonts->Add(new RFont(this, fd->Fid(), fd->Face()));
  905. }
  906.  
  907. void PostScriptPort::UseProcSet(char *name)
  908. {
  909.     Iter next(ProcSets);
  910.     register ProcSet *ps;
  911.     
  912.     while (ps= (ProcSet*) next())
  913.     if (strcmp(name, ps->GetName()) == 0)
  914.         return;
  915.         
  916.     ProcSets->Add(new ProcSet(name, pst->prolog));
  917. }
  918.  
  919. void PostScriptPort::downloadfont(FILE *ofp, Font *fd, char *fname)
  920. {
  921.     int z, i, x, y, ps, llx, lly, urx, ury, bytesperline;
  922.     DevBitmap *dbm;
  923.     Point offset, size;
  924.     
  925.     llx= lly= 9999;
  926.     urx= ury= 0;
  927.     ps= fd->Size();
  928.  
  929.     Printf(ofp, "%%%%BeginFont: %s\n", fname);
  930.     Printf(ofp, "/%s %d %d [\n", fname, cFirstFontId+fd->Fid()*256+fd->Face(), ps);
  931.     for (z= i= 0; i < cCharsPerFont; i++) {
  932.     if ((dbm= fd->CharAsBitmap(i, &offset)) == 0)
  933.         continue;
  934.     dbm->Ref();
  935.     size= dbm->Size();
  936.        
  937.     llx= Math::Min(llx, offset.x);
  938.     lly= Math::Min(lly, offset.y);
  939.     urx= Math::Max(urx, offset.x+size.x);
  940.     ury= Math::Max(ury, offset.y+size.y);
  941.     
  942.     Printf(ofp, "<%x%x%x%x%x%x", i, fd->Width(i), size.x, size.y, offset.x,
  943.                                 offset.y-size.y);
  944.     
  945.     if (pst->smooth) {
  946.         UseProcSet("smooth 2.2 0");
  947.         bytesperline= (((size.x+2)-1)/16+1)*2;
  948.         for (y= -2; y < size.y+2; y++) {
  949.         for (x= 0; x < bytesperline; x++)
  950.             Printf(ofp, "%x", dbm->GetByte(x, y));
  951.         }
  952.     } else {
  953.         bytesperline= (size.x-1) / 8 + 1;
  954.         for (y= 0; y < size.y; y++)
  955.         for (x= 0; x < bytesperline; x++)
  956.             Printf(ofp, "%x", dbm->GetByte(x, y));
  957.     }
  958.         
  959.     Printf(ofp, ">\n");
  960.     z++;
  961.     dbm->Unref();
  962.     }
  963.     Printf(ofp, "] %d %d %d %d %d new%sbitmapfont\n", z, llx, lly, urx, ury,
  964.                         pst->smooth ? "smoothed" : "");
  965.     Printf(ofp, "%%%%EndFont\n");
  966. }
  967.  
  968. //---- PostScriptPrinter -------------------------------------------------------
  969.  
  970. NewMetaImpl(PostScriptPrinter, Printer, (TP(orientation), TP(resolution), TP(options), TP(eti)));
  971.  
  972. void PostScriptPrinter::LoadSettings(PrinterSettings *ps)
  973. {
  974.     if (eti) {
  975.     PostScriptSettings *settings= (PostScriptSettings*) ps;
  976.     options->SetItem(cIdOptions+0, settings->smooth);
  977.     options->SetItem(cIdOptions+1, settings->wysiwyg);
  978.     options->SetItem(cIdOptions+2, settings->prolog);
  979.     resolution->SetValue(settings->resolution*100.0);
  980.     orientation->SetItemOn(cIdOrientation + (settings->portrait ? 0 : 1));
  981.     eti->SetString(settings->prname);
  982.     
  983.     Point pap= settings->paperSize;
  984.     if (!settings->portrait)
  985.         pap= Flip(pap);
  986.     
  987.     for (int i= 0; paperFormats[i].name; i++)
  988.         if (paperFormats[i].Size() == pap)
  989.         break;
  990.     if (paperFormats[i].name == 0)
  991.         paperFormatMenu->AppendItem(form("%d x %d points", pap.x, pap.y), i);
  992.     paperFormatPopup->SetValue(i);
  993.     }
  994. }
  995.  
  996. void PostScriptPrinter::StoreSettings(PrinterSettings *ps)
  997. {
  998.     PostScriptSettings *settings= (PostScriptSettings*) ps;
  999.     settings->smooth= options->IsItemOn(cIdOptions+0);
  1000.     settings->wysiwyg= options->IsItemOn(cIdOptions+1);
  1001.     settings->prolog= options->IsItemOn(cIdOptions+2);
  1002.     settings->resolution= resolution->GetValue()/100.0;
  1003.  
  1004.     int si= paperFormatPopup->GetValue();
  1005.     int maxsize= (sizeof(paperFormats)/sizeof(PaperFormat))-1;
  1006.     if (si >= 0 && si < maxsize)
  1007.     settings->SetPaperSize(paperFormats[si].Size());
  1008.     paperFormatMenu->RemoveItem(maxsize);
  1009.  
  1010.     settings->portrait= orientation->GetCurrentItem() == cIdOrientation;
  1011.     if (!settings->portrait)
  1012.     settings->SetPaperSize(Flip(settings->GetPaperSize()));
  1013.  
  1014.     SafeDelete(settings->prname);
  1015.     settings->prname= strsave(eti->AsString());
  1016. }
  1017.  
  1018. VObject *PostScriptPrinter::DoCreatePrintDialog()
  1019. {
  1020.     orientation=
  1021.     new OneOfCluster(cIdOrientation, eVObjHLeft, 5,
  1022.         "Portrait",
  1023.         "Landscape",
  1024.         0
  1025.     );
  1026.     
  1027.     options=
  1028.     new ManyOfCluster(cIdOptions, eVObjHLeft, 5,
  1029.         "Smooth Bitmaps",
  1030.         "Smooth Text",
  1031.         "Include ProcSets",
  1032.         0
  1033.     );
  1034.             
  1035.     paperFormatMenu= new Menu("Paper Formats", FALSE);
  1036.     for (int i= 0; paperFormats[i].name; i++)
  1037.     paperFormatMenu->AppendItem(paperFormats[i].name, i);
  1038.  
  1039.     //---- overall layout ----
  1040.     return
  1041.     new VExpander(10, 
  1042.         new HBox(10, eVObjVTop,
  1043.         new BorderItem("Options", options),
  1044.         new BorderItem("Orientation", orientation),
  1045.         0
  1046.         ),
  1047.         new Form(cIdNone, eVObjHCenter, 2,
  1048.         "Paper:", paperFormatPopup= new PopupButton(cIdPaperFormat,
  1049.                             0, paperFormatMenu),
  1050.         "Scale:", resolution= new FloatField(cIdResolution, 100.0, 400.0, "%g %%"),
  1051.         "Printer Name:", eti= new TextField(cIdName, 10),
  1052.         0
  1053.         ),
  1054.         0
  1055.     );
  1056. }
  1057.  
  1058.